home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-26 | 73.6 KB | 3,889 lines |
- =====================================================================
-
- ... GAVIN'S GUIDE TO 80x86 ASSEMBLY
-
- =====================================================================
-
- .Copyright (c) Gavin Estey, 1995. All rights reserved.
-
-
- This was originally written for the Game Developer's Magazine and
-
- after getting lots of positive feedback I added and expanded it. I
-
- have spent a lot of time working on it and I would appreciate
-
- hearing from you if you like it.
-
-
- If you want to contact me then email me at:
-
-
- gavin@senator.demon.co.uk or on CompuServe 100767,1325
-
-
-
-
- RESOURCES THAT WOULD BE USEFUL
-
- ---------------------------------------------------------------------
-
-
- There are several resources that you may find useful:
-
-
- List of Instructions and timings:
-
-
- If you have TASM then the "Borland Turbo Assembler Quick Reference"
-
- has a list of instructions and timings up to 486. The "Intel Pentium
-
- Family User's Manual: Volume 3" is equally useful.
-
-
- List of Interrupts:
-
-
- There are several books that have this information but the most up to
-
- date is Ralf Brown's Interrupt list available freely in four parts at
-
- ftp://x2ftp.oulu.fi/pub/msdos/programming/docs/interXX[a-d].zip where
-
- XX is the version.
-
-
- A book that covers both these topics and is a useful assembly
-
- reference is "The Revolutionary guide to Assembly Language",
-
- ISBN 1-874416-12-5 publised by WROX Press.
-
-
-
- OVERVIEW OF THE 80x86 FAMILY
-
- ---------------------------------------------------------------------
-
-
- The 80x86 family was first started in 1981 with the 8086 and the
-
- newest member is the Pentium which was released thirteen years later
-
- in 1994. They are all backwards compatible with each other but each
-
- new generation has added features and more speed than the previous
-
- chip. Today there are very few computers in use that have the 8088
-
- and 8086 chips in them as they are very outdated and slow. There are
-
- a few 286's but their numbers are declining as today's software
-
- becomes more and more demanding. Even the 386, Intel's first 32-bit
-
- CPU, is now declining and it seems that the 486 is now the entry
-
- level system.
-
-
- Representation of numbers in binary
-
- ---------------------------------------------------------------------
-
-
- Before we begin to understand how to program in assembly it is best
-
- to try to understand how numbers are represented in computers.
-
- Numbers are stored in binary, base two. There are several terms which
-
- are used to describe different size numbers and I will describe
-
- what these mean.
-
-
- 1 BIT: 0
-
-
- One bit is the simplest piece of data that exists. Its either a one
-
- or a zero.
-
-
- 1 NIBBLE: 0000
-
- 4 BITS
-
-
- The nibble is four bits or half a byte. Note that it has a maximum
-
- value of 15 (1111 = 15). This is the basis for the hexadecimal (base
-
- 16) number system which is used as it is far easier to understand.
-
- Hexadecimal numbers go from 1 to F and are followed by a h to
-
- state that the are in hex. i.e. Fh = 15 decimal. Hexadecimal numbers
-
- that begin with a letter are prefixed with a 0 (zero).
-
-
- 1 BYTE 00000000
-
- 2 NIBBLES
-
- 8 BITS
-
-
- A byte is 8 bits or 2 nibbles. A byte has a maximum value of FFh
-
- (255 decimal). Because a byte is 2 nibbles the hexadecimal
-
- representation is two hex digits in a row i.e. 3Dh. The byte is also
-
- that size of the 8-bit registers which we will be covering later.
-
-
- 1 WORD 0000000000000000
-
- 2 BYTES
-
- 4 NIBBLES
-
- 16 BITS
-
-
- A word is two bytes that are stuck together. A word has a maximum
-
- value of FFFFh (65,536). Since a word is four nibbles, it is
-
- represented by four hex digits. This is the size of the 16-bit
-
- registers.
-
-
- Registers
-
- ---------------------------------------------------------------------
-
-
- Registers are a place in the CPU where a number can be stored and
-
- manipulated. There are three sizes of registers: 8-bit, 16-bit and
-
- on 386 and above 32-bit. There are four different types of
-
- registers; general purpose registers, segment registers, index
-
- registers and stack registers. Firstly here are descriptions of the
-
- main registers. Stack registers and segment registers will be
-
- covered later.
-
-
- General Purpose Registers
-
- ---------------------------------------------------------------------
-
-
- These are 16-bit registers. There are four general purpose registers;
-
- AX, BX, CX and DX. They are split up into 8-bit registers. AX is split
-
- up into AH which contains the high byte and AL which contains the low
-
- byte. On 386's and above there are also 32-bit registers, these have
-
- the same names as the 16-bit registers but with an 'E' in front i.e.
-
- EAX. You can use AL, AH, AX and EAX separatly and treat them as
-
- separate registers for some tasks.
-
-
- If AX contained 24689 decimal:
-
-
-
- AH AL
-
- 01100000 01110001
-
-
- AH would be 96 and AL would be 113. If you added one to AL it would
-
- be 114 and AH would be unchanged.
-
-
- SI, DI, SP and BP can also be used as general purpose registers but
-
- have more specific uses. They are not split into two halves.
-
-
- Index Registers
-
- ---------------------------------------------------------------------
-
-
- These are sometimes called pointer registers and they are 16-bit
-
- registers. They are mainly used for string instructions. There are
-
- three index registers SI (source index), DI (destination index) and
-
- IP (instruction pointer). On 386's and above there are also 32-bit
-
- index registers: EDI and ESI. You can also use BX to index strings.
-
- IP is a index register but it can't be manipulated directly as it
-
- stores the address of the next instruction.
-
-
- Stack registers
-
- ---------------------------------------------------------------------
-
-
- BP and SP are stack registers and are used when dealing with the
-
- stack. They will be covered when we talk about the stack later on.
-
-
- Segments and offsets
-
- ---------------------------------------------------------------------
-
-
- The original designers of the 8088 decided that nobody will ever
-
- need to use more that one megabyte of memory so they built the chip
-
- so it couldn't access above that. The problem is to access a whole
-
- megabyte 20 bits are needed. Registers only have 16 bits and they
-
- didn't want to use two because that would be 32 bits and they
-
- thought that this would be too much for anyone. They came up with
-
- what they thought was a clever way to solve this problem: segments
-
- and offsets. This is a way to do the addressing with two registers
-
- but not 32 bits.
-
-
- OFFSET = SEGMENT * 16
-
- SEGMENT = OFFSET / 16 (the lower 4 bits are lost)
-
-
- One register contains the segment and another register contains the
-
- offset. If you put the two registers together you get a 20-bit
-
- address.
-
-
- SEGMENT 0010010000010000----
-
- OFFSET ----0100100000100010
-
- 20-bit Address 00101000100100100010
-
- ..====== DS ======
-
- .. ====== SI ======
-
- ..
-
- Notice that DS and SI overlap. This is how DS:SI is used to make a
-
- 20 bit address. The segment is in DS and the offset is in SI. The
-
- standard notation for a Segment/Offset pair is: SEGMENT:OFFSET
-
-
- Segment registers are: CS, DS, ES, SS. On the 386+ there are also FS
-
- and GS.
-
-
- Offset registers are: BX, DI, SI, BP, SP, IP. In 386+ protected
-
- mode1, ANY general register (not a segment register) can be used as
-
- an Offset register. (Except IP, which you can't manipulate
-
- directly).
-
-
- If you are now thinking that assembly must be really hard and you
-
- don't understand segments and offsets at all then don't worry. I
-
- didn't understand them at first but I struggled on and found out
-
- that they were not so hard to use in practice.
-
-
- THE STACK
-
- ---------------------------------------------------------------------
-
-
- As there are only six registers that are used for most operations,
-
- you're probably wondering how do you get around that. It's easy.
-
- There is something called a stack which is an area of memory which
-
- you can save and restore values to.
-
-
- This is an area of memory that is like a stack of plates. The last
-
- one you put on is the first one that you take off. This is sometimes
-
- refered to as Last On First Off (LOFO) or First In First Out (LIFO).
-
- If another piece of data is put on the stack it grows downwards.
-
-
- As you can see the stack starts at a high address and grows
-
- downwards. You have to make sure that you don't put too much data in
-
- the stack or it will overflow.
-
-
- AN INTRODUCTION TO ASSEMBLY INSTRUCTIONS
-
- ---------------------------------------------------------------------
-
-
- There are a lot of instructions in assembly but there are only about
-
- twenty that you have to know and will use very often. Most
-
- instructions are made up of three characters and have an operand then
-
- a comma then another operand. For example to put a data into a
-
- register you use the MOV instruction.
-
-
- .mov ax,10 ;put 10 into ax
-
- .mov bx,20 ;put 20 into bx
-
- .mov cx,30 ;put 30 into cx
-
- .mov dx,40 ;put 40 into dx
-
-
- Notice that in assembler anything after a ; (semicolon) is ignored.
-
- This is very useful for commenting your code.
-
-
- PUSH AND POP: TWO INSTRUCTIONS TO USE THE STACK
-
- ---------------------------------------------------------------------
-
-
- You know about the stack but not how to put data in an out of it.
-
- There are two simple instructions that you need to know: push and
-
- pop. Here is the syntax for their use:
-
-
- PUSH Puts a piece of data onto the top of the stack
-
-
- Syntax:
-
- .push data
-
-
- POP Puts the piece of data from the top of the stack into a
-
- specified register or variable.
-
-
- Syntax:
-
- .pop register or variable
-
- .
-
- This example of code demonstrates how to use the push and pop
-
- instructions
-
-
- .push cx ;put cx on the stack
-
- .push ax ;put ax on the stack
-
- .pop cx ;put value from stack into cx
-
- .pop ax ;put value from stack into ax
-
-
- Notice that the values of CX and AX will be exchanged. There is an
-
- instruction to exchange two registers: XCHG, which would reduce the
-
- previous fragment to "xchg ax,cx".
-
-
- TYPES OF OPERAND
-
- ---------------------------------------------------------------------
-
-
- There are three types of operands in assembler: immediate, register
-
- and memory. Immediate is a number which will be known at compilation
-
- and will always be the same for example '20' or 'A'. A register
-
- operand is any general purpose or index register for example AX or
-
- SI. A memory operand is a variable which is stored in memory which
-
- will be covered later.
-
-
- SOME INSTRUCTIONS THAT YOU WILL NEED TO KNOW
-
- ---------------------------------------------------------------------
-
-
- This is a list of some important instructions that you need to know
-
- before you can understand or write assembly programs.
-
-
- MOV moves a value from one place to another.
-
-
- Syntax:
-
- .MOV destination, source
-
-
- for example:
-
- .mov ax,10 ;moves an immediate value into ax
-
- .mov bx,cx ;moves value from cx into bx
-
- .mov dx,Number ;moves the value of Number into dx
-
-
- INT calls a DOS or BIOS function which are subroutines to do
-
- things that we would rather not write a function for e.g.
-
- change video mode, open a file etc.
-
-
- Syntax:
-
- .INT interrupt number
-
-
- For example:
-
- .int 21h ;Calls DOS service
-
- .int 10h ;Calls the Video BIOS interrupt
-
-
- Most interrupts have more than one function, this means that you
-
- have to pass a number to the function you want. This is usually put
-
- in AH. To print a message on the screen all you need to do is this:
-
-
- .mov ah,9 ;subroutine number 9
-
- .int 21h ;call the interrupt
-
-
- But first you have to specify what to print. This function needs
-
- DS:DX to be a far pointer to where the string is. The string has to
-
- be terminated with a dollar sign ($). This would be easy if DS could
-
- be manipulated directly, to get round this we have to use AX.
-
-
- This example shows how it works:
-
- .
-
- .mov dx,OFFSET Message ;DX contains offset of message
-
- .mov ax,SEG Message ;AX contains segment of message
-
- .mov ds,ax ;DS:DX points to message
-
- .mov ah,9 ;function 9 - display string
-
- .int 21h ;call dos service
-
-
- The words OFFSET and SEG tell the compiler that you want the
-
- segment or the offset of the message put in the register not the
-
- contents of the message. Now we know how to set up the code to
-
- display the message we need to declare the message. In the data
-
- segment1 we declare the message like this:
-
-
- .Message DB "Hello World!$"
-
-
- Notice that the string is terminated with an dollar sign. What does
-
- 'DB' mean? DB is short for declare byte and the message is an array
-
- of bytes (an ASCII character takes up one byte). Data can be
-
- declared in a number of sizes: bytes (DB), words (DW) and double
-
- words (DD). You don't have to worry about double words at the moment
-
- as you need a 32-bit register, such as EAX, to fit them in.
-
-
- Here are some examples of declaring data:
-
- .
-
- .Number1 db ?
-
- .Number2 dw ?
-
-
- The question mark (?) on the end means that the data isn't
-
- initialised i.e. it has no value in to start with. That could as
-
- easily be written as:
-
-
- .Number1 db 0
-
- .Number2 dw 1
-
-
- This time Number1 is equal to 0 and Number2 is equal to 1 when you
-
- program loads. Your program will also be three bytes longer. If you
-
- declare a variable as a word you cannot move the value of this
-
- variable into a 8-bit register and you can't declare a variable
-
- as a byte and move the value into a 16-bit register. For examples:
-
-
- .mov al,Number1 ;ok
-
- .mov ax,Number1 ;error
-
-
- .mov bx,Number2 ;ok
-
- .mov bl,Number2 ;error
-
-
- All you have to remember is that you can only put bytes into 8-bit
-
- registers and words into 16-bit registers.
-
-
- YOUR FIRST ASSEMBLY PROGRAM
-
- ---------------------------------------------------------------------
-
-
- Now that you know some basic instructions and a little about data it
-
- is time that we looked at a full assembly program which can be
-
- compiled.
-
-
- Listing 1: 1STPROG.ASM
-
-
- ;This is a simple program which displays "Hello World!" on the
-
- ;screen.
-
-
- .model small
-
- .stack
-
- .data
-
-
-
- Message db "Hello World!$" ;message to be display
-
-
- .code
-
- .mov dx,OFFSET Message ;offset of Message is in DX
-
- .mov ax,SEG Message ;segment of Message is in AX
-
- mov ds,ax ;DS:DX points to string
-
- mov ah,9 ;function 9 - display string
-
- int 21h ;call dos service
-
-
- mov ax,4c00h ;return to dos DOS
-
- int 21h
-
- .
-
- END start ;end here
-
-
- COMPILATION INSTRUCTIONS
-
- ---------------------------------------------------------------------
-
-
- These are some instructions to compile and link programs. If you
-
- have a compiler other than TASM or A86 then see your instruction
-
- manual.
-
-
- Turbo Assembler:
-
-
- .tasm file.asm
-
- .tlink file [/t]
-
-
- The /t switch makes a .COM file. This will only work if the memory
-
- model is declared as tiny in the source file.
-
-
- A86:
-
-
- .a86 file.asm
-
-
- This will compile your program to a .COM file. It doesn't matter
-
- what the memory model is.
-
-
- SOME INSTRUCTIONS THAT YOU NEED TO KNOW
-
- ---------------------------------------------------------------------
-
-
- This is just a list of some basic assembly instructions that are
-
- very important and are used often.
-
-
- ADD Add the contents of one number to another
-
-
- Syntax:
-
-
- .ADD operand1,operand2
-
-
- This adds operand2 to operand1. The answer is stored in operand1.
-
- Immediate data cannot be used as operand1 but can be used as
-
- operand2.
-
-
- SUB Subtract one number from another
-
-
- Syntax:
-
- .SUB operand1,operand2
-
-
- This subtracts operand2 from operand1. Immediate data cannot be used
-
- as operand1 but can be used as operand2.
-
-
- MUL Multiplies two unsigned integers (always positive)
-
- IMUL Multiplies two signed integers (either positive or negitive)
-
-
- Syntax:
-
- .MUL register or variable
-
- .IMUL register or variable
-
-
- This multiples AL or AX by the register or variable given. AL is
-
- multiplied if a byte sized operand is given and the result is stored
-
- in AX. If the operand is word sized AX is multiplied and the result
-
- is placed in DX:AX.
-
-
- On a 386, 486 or Pentium the EAX register can be used and the answer
-
- is stored in EDX:EAX.
-
-
- DIV Divides two unsigned integers (always positive)
-
- IDIV Divides two signed integers (either positive or negitive)
-
-
- Syntax:
-
- .DIV register or variable
-
- .IDIV register or variable
-
-
- This works in the same way as MUL and IMUL by dividing the number in
-
- AX by the register or variable given. The answer is stored in two
-
- places. AL stores the answer and the remainder is in AH. If the
-
- operand is a 16 bit register than the number in DX:AX is
-
- divided by the operand and the answer is stored in AX and remainder
-
- in DX.
-
-
- MAKING THINGS EASIER
-
- ---------------------------------------------------------------------
-
-
- The way we entered the address of the message we wanted to print was
-
- a bit cumbersome. It took three lines and it isn't the easiest thing
-
- to remember
-
-
- .mov dx,OFFSET MyMessage
-
- .mov ax,SEG MyMessage
-
- .mov ds,ax
-
-
- We can replace all this with just one line. This makes the code
-
- easier to read and it easier to remember.
-
-
- .mov dx,OFFSET MyMessage
-
-
- To make this work at the beginning of your code add these lines:
-
- .
-
- .mov ax,@data
-
- .mov ds,ax
-
-
- Note: for A86 you need to change the first line to:
-
-
- .mov ax,data
-
-
- This is because all the data in the segment has the same SEG value.
-
- Putting this in DS saves us reloading this every time we want to
-
- use another thing in the same segment.
-
-
- KEYBOARD INPUT
-
- ---------------------------------------------------------------------
-
-
- We are going to use interrupt 16h, function 00h to read the
-
- keyboard. This gets a key from the keyboard buffer. If there isn't
-
- one, it waits until there is. It returns the SCAN code in AH and the
-
- ASCII translation in AL.
-
-
- .xor ah,ah ;function 00h - get character
-
- .int 16h ;interrupt 16h
-
-
- All we need to worry about for now is the ascii value which is in AL.
-
-
- Note: XOR performs a Boolean Exclusive OR. It is commonly used to
-
- erase a register or variable.
-
-
- PRINTING A CHARACTER
-
- ---------------------------------------------------------------------
-
-
- The problem is that we have the key that has been pressed in ah. How
-
- do we display it? We can't use function 9h because for that we need
-
- to have already defined the string which has to end with a dollar
-
- sign. This is what we do instead:
-
-
- ;after calling function 00h of interrupt 16h
-
-
- .mov dl,al ;move al (ascii code) into dl
-
- .mov ah,02h ;function 02h of interrupt 21h
-
- .int 21h ;call interrupt 21h
-
-
- If you want to save the value of AH then push AX before and pop it
-
- afterwards.
-
-
- CONTROL FLOW
-
- ---------------------------------------------------------------------
-
-
- In assembly there is a set of commands for control flow like in any
-
- other language. Firstly the most basic command:
-
- .
-
- .jmp label
-
-
- All this does it to move to the label specified and start executing
-
- the code there. For example:
-
-
- .jmp ALabel
-
- ..
-
- ..
-
- ..
-
- .ALabel:
-
-
-
- What do we do if we want to compare something? We have just got a
-
- key from the user but we want to do something with it. Lets print
-
- something out if it is equal to something else. How do we do that?
-
- It is easy. We use the jump on condition commands. Here is a list
-
- of them:
-
-
- JUMP ON CONDITION INSTRUCTIONS:
-
-
- JA jumps if the first number was above the second number
-
- JAE same as above, but will also jump if they are equal
-
- JB jumps if the first number was below the second
-
- JBE same as above, but will also jump if they are equal
-
- JNA jumps if the first number was NOT above (JBE)
-
- JNAE jumps if the first number was NOT above or the same as (JNB)
-
- JNB jumps if the first number was NOT below (JAE)
-
- JNBE jumps if the first number was NOT below or the same as (JA)
-
- JZ jumps if the two numbers were equal
-
- JE same as JZ, just a different name
-
- JNZ jumps if the two numbers are NOT equal
-
- JNE same as above
-
- JC jump if carry flag is set
-
- .
-
- Note: the jump can only be a maximum of 127 bytes in either
-
- direction.
-
-
- Syntax:
-
- .CMP register or variable, value
-
- .jxx destination
-
-
- An example of this is:
-
-
- cmp al,'Y' ;compare the value in al with Y
-
- je ItsYES ;if it is equal then jump to ItsYES
-
-
- Every instruction takes up a certain amount of code space. You will
-
- get a warning if you try and jump over 127 bytes in either direction
-
- from the compiler. You can solve this by changing a sequence like this:
-
-
- .cmp ax,10 ;is AX 10?
-
- .je done ;yes, lets finish
-
-
- to something like this:
-
-
- .cmp ax,10 ;is AX 10?
-
- .jne notdone ;no it is not
-
- .jmp done ;we are now done
-
- notdone:
-
- .
-
- This solves the problem but you may want to think about reordering
-
- your code or using procedures if this happens often.
-
-
- Now we are going to look at a program which demonstrates input,
-
- output and control flow.
-
-
- Listing 2: PROGFLOW.ASM
-
-
- ;a program to demonstrate program flow and input/output
-
- .model tiny
-
- .code
-
- org 100h
-
- start:
-
-
- .mov dx,OFFSET Message ;display a message on the screen
-
- .mov ah,9 ;using function 09h
-
- .int 21h ;of interrupt 21h
-
-
-
- .mov dx,OFFSET Prompt ;display a message on the screen
-
- .mov ah,9 ;using function 09h
-
- .int 21h ;of interrupt 21h
-
- .jmp First_Time
-
-
- Prompt_Again:
-
- .mov dx,OFFSET Another ;display a message on the screen
-
- .mov ah,9 ;using function 09h
-
- .int 21h ;of interrupt 21h
-
-
-
- First_Time:
-
- mov dx,OFFSET Again ;display a message on the screen
-
- mov ah,9 ;using function 09h
-
- int 21h ;of interrupt 21h
-
-
-
- xor ah,ah ;function 00h of
-
- int 16h ;interrupt 16h gets a character
-
- mov bl,al ;save to bl
-
-
-
- mov dl,al ;move al to dl
-
- mov ah,02h ;function 02h - display character
-
- int 21h ;call DOS service
-
-
-
- cmp bl,'Y' ;is al=Y?
-
- je Prompt_Again ;if yes then display it again
-
- cmp bl,'y' ;is al=y?
-
- je Prompt_Again ;if yes then display it again
-
-
-
- TheEnd:
-
- mov dx,OFFSET GoodBye ;print goodbye message
-
- mov ah,9 ;using function 9
-
- int 21h ;of interrupt 21h
-
- mov ah,4Ch ;terminate program DOSusing
-
- int 21h
-
-
- .DATA
-
- CR equ 13 ;enter
-
- LF equ 10 ;line-feed
-
-
- Message DB "A Simple Input/Output Program$"
-
- Prompt DB CR,LF,"Here is your first prompt.$"
-
- Again DB CR,LF,"Do you want to be prompted again? $"
-
- Another DB CR,LF,"Here is another prompt!$"
-
- GoodBye DB CR,LF,"Goodbye then.$"
-
- end start
-
-
- INTRODUCTION TO PROCEDURES
-
- ---------------------------------------------------------------------
-
-
- In assembly a procedure is the equivalent to a function in C or
-
- Pascal. A procedure provides a easy way to encapsulate some
-
- calculation which can then be used without worrying how it works.
-
- With procedures that are properly designed you can ignore how a
-
- job is done.
-
-
- This is how a procedure is defined:
-
-
- PROC AProcedure
-
- .
-
- . ;some code to do something
-
- .
-
- RET ;if this is not here then your computer will crash
-
- ENDP AProcedure
-
-
- It is equally easy to run a procedure all you need to do is this:
-
-
- .call AProcedure
-
-
- This next program is an example of how to use a procedure. It is
-
- like the first example we looked at, all it does is print "Hello
-
- World!" on the screen.
-
-
- Listing 3: SIMPPROC.ASM
-
-
- ;This is a simple program to demonstrate procedures. It should
-
- ;print Hello World! on the screen when ran.
-
-
- .model tiny
-
- .code
-
- org 100h
-
-
- Start:
-
- .call Display_Hi ;Call the procedure
-
- .mov ax,4C00h ;return to DOS
-
- .int 21h ;interrupt 21h function 4Ch
-
-
- Display_Hi PROC
-
- .mov dx,OFFSET HI ;put offset of message into DX
-
- .mov ah,9 ;function 9 - display string
-
- .int 21h ;call DOS service
-
- .ret
-
- Display_Hi ENDP
-
-
- HI DB "Hello World!$" ;define a message
-
-
- end Start
-
-
-
- PROCEDURES THAT PASS PARAMETERS
-
- ---------------------------------------------------------------------
-
-
- Procedures wouldn't be so useful unless you could pass parameters to
-
- modify or use inside the procedure. There are three ways of doing
-
- this and I will cover all three methods: in registers, in memory and
-
- in the stack.
-
-
- There are three example programs which all accomplish the same task.
-
- They print a square block (ASCII value 254) in a specified place.
-
- The sizes of the files when compiled are: 38 for register, 69 for
-
- memory and 52 for stack.
-
-
- In registers
-
- ---------------------------------------------------------------------
-
-
- The advantages of this is that it is easy to do and is fast. All you
-
- have to do is to is move the parameters into registers before
-
- calling the procedure.
-
-
- Listing 4: PROC1.ASM
-
-
- ;this a procedure to print a block on the screen using
-
- ;registers to pass parameters (cursor position of where to
-
- ;print it and colour).
-
-
- .model tiny
-
- .code
-
- org 100h
-
- Start:
-
- .mov dh,4 ;row to print character on
-
- .mov dl,5 ;column to print character on
-
- .mov al,254 ;ascii value of block to display
-
- .mov bl,4 ;colour to display character
-
-
- .call PrintChar ;print our character
-
-
- .mov ax,4C00h ;terminate program
-
- .int 21h
-
-
- PrintChar PROC NEAR
-
- .push cx ;save registers to be destroyed
-
-
- .xor bh,bh ;clear bh - video page 0
-
- .mov ah,2 ;function 2 - move cursor
-
- .int 10h ;row and col are already in dx
-
-
- .pop bx ;restore bx
-
- .xor bh,bh ;display page - 0
-
- .mov ah,9 ;function 09h write char & attrib
-
- .mov cx,1 ;display it once
-
- .int 10h ;call bios service
-
-
- .pop cx ;restore registers
-
- .ret ;return to where it was called
-
- PrintChar ENDP
-
-
- end Start
-
-
- PASSING THROUGH MEMORY
-
- ---------------------------------------------------------------------
-
-
- The advantages of this method is that it is easy to do but it makes
-
- your program larger and can be slower.
-
-
- To pass parameters through memory all you need to do is copy them to
-
- a variable which is stored in memory. You can use a variable in the
-
- same way that you can use a register but commands with registers are
-
- a lot faster.
-
-
- Listing 5: PROC2.ASM
-
-
- ;this a procedure to print a block on the screen using memory
-
- ;to pass parameters (cursor position of where to print it and
-
- ;colour).
-
-
- .model tiny
-
- .code
-
- org 100h
-
- Start:
-
- mov Row,4 ;row to print character
-
- mov Col,5 ;column to print character on
-
- mov Char,254 ;ascii value of block to display
-
- mov Colour,4 ;colour to display character
-
-
- call PrintChar ;print our character
-
-
- mov ax,4C00h ;terminate program
-
- int 21h
-
-
- PrintChar PROC NEAR
-
- push ax cx bx ;save registers to be destroyed
-
-
- xor bh,bh ;clear bh - video page 0
-
- mov ah,2 ;function 2 - move cursor
-
- mov dh,Row
-
- mov dl,Col
-
- int 10h ;call Bios service
-
- .
-
- mov al,Char
-
- mov bl,Colour
-
- xor bh,bh ;display page - 0
-
- mov ah,9 ;function 09h write char & attrib
-
- mov cx,1 ;display it once
-
- int 10h ;call bios service
-
-
- pop bx cx ax ;restore registers
-
- ret ;return to where it was called
-
- PrintChar ENDP
-
-
- Row db ? ;variables to store data
-
- Col db ?
-
- Colour db ?
-
- Char db ?
-
-
- end Start
-
-
- Passing through Stack
-
- ---------------------------------------------------------------------
-
-
- This is the most powerful and flexible method of passing parameters
-
- the problem is that it is more complicated.
-
-
- Listing 6: PROC3.ASM
-
-
- ;this a procedure to print a block on the screen using the
-
- ;stack to pass parameters (cursor position of where to print it
-
- ;and colour).
-
-
- .model tiny
-
- .code
-
- org 100h
-
- Start:
-
- .mov dh,4 ;row to print string on
-
- .mov dl,5 ;column to print string on
-
- .mov al,254 ;ascii value of block to display
-
- .mov bl,4 ;colour to display character
-
-
- .push dx ax bx ;put parameters onto the stack
-
- .call PrintString ;print our string
-
- .pop bx ax dx ;restore registers
-
-
- .mov ax,4C00h ;terminate program
-
- .int 21h
-
-
- PrintString PROC NEAR
-
- .push bp ;save bp
-
- .mov bp,sp ;put sp into bp
-
- .push cx ;save registers to be destroyed
-
-
- .xor bh,bh ;clear bh - video page 0
-
- .mov ah,2 ;function 2 - move cursor
-
- .mov dx,[bp+8] ;restore dx
-
- .int 10h ;call bios service
-
-
- .mov ax,[bp+6] ;character
-
- .mov bx,[bp+4] ;attribute
-
- .xor bh,bh ;display page - 0
-
- .mov ah,9 ;function 09h write char & attrib
-
- .mov cx,1 ;display it once
-
- .int 10h ;call bios service
-
-
- .pop cx ;restore registers
-
- .pop bp
-
- .ret ;return to where it was called
-
- PrintString ENDP
-
-
- end Start
-
-
- To get a parameter from the stack all you need to do is work out
-
- where it is. The last parameter is at BP+2 and then the next and
-
- BP+4.
-
-
- WHAT ARE MEMORY MODELS?
-
- ---------------------------------------------------------------------
-
-
- We have been using the .MODEL directive to specify what type of
-
- memory model we use, but what does this mean?
-
-
- Syntax:
-
- ..MODEL MemoryModel
-
-
- Where MemoryModel can be SMALL, COMPACT, MEDIUM, LARGE, HUGE, TINY
-
- OR FLAT.
-
-
- Tiny
-
-
- This means that there is only one segment for both code and data.
-
- This type of program can be a .COM file.
-
-
- Small
-
-
- This means that by default all code is place in one segment and all
-
- data declared in the data segment is also placed in one segment.
-
- This means that all procedures and variables are addressed as NEAR
-
- by pointing at offsets only.
-
-
- Compact
-
-
- This means that by default all elements of code are placed in one
-
- segment but each element of data can be placed in its own physical
-
- segment. This means that data elements are addressed by pointing at
-
- both at the segment and offset addresses. Code elements (procedures)
-
- are NEAR and variables are FAR.
-
-
- Medium
-
-
- This is the opposite to compact. Data elements are NEAR and
-
- procedures are FAR.
-
-
- Large
-
-
- This means that both procedures and variables are FAR. You have to
-
- point at both the segment and offset addresses.
-
-
- Flat
-
-
- This isn't used much as it is for 32 bit unsegmented memory space.
-
- For this you need a DOS extender. This is what you would have to use
-
- if you were writing a program to interface with a C/C++ program that
-
- used a DOS extender such as DOS4GW or PharLap.
-
-
- MACROS (in Turbo Assembler)
-
- ---------------------------------------------------------------------
-
-
- (All code examples given are for macros in Turbo Assembler.)
-
-
- Macros are very useful for doing something that is done often but
-
- for which a procedure can't be use. Macros are substituted when the
-
- program is compiled to the code which they contain.
-
-
- This is the syntax for defining a macro:
-
-
- Name_of_macro macro
-
- ;
-
- ;a sequence of instructions
-
- ;
-
- endm
-
-
- These two examples are for macros that take away the boring job of
-
- pushing and popping certain registers:
-
-
- .SaveRegs macro
-
- ..pop ax
-
- ..pop bx
-
- ..pop cx
-
- ..pop dx
-
- .endm
-
- .
-
- .RestoreRegs macro
-
- ..pop dx
-
- ..pop cx
-
- ..pop bx
-
- ..pop ax
-
- .
-
- .endm
-
-
- Note that the registers are popped in the reverse order to they were
-
- pushed. To use a macro in you program you just use the name of the
-
- macro as an ordinary instruction:
-
-
- .SaveRegs
-
- .;some other instructions
-
- .RestoreRegs
-
-
- This example shows how you can use a macro to save typing in. This
-
- macro simply prints out a message to the screen.
-
-
- OutMsg macro SomeText
-
- .local PrintMe,SkipData
-
- .jmp SkipData
-
-
- PrintMe db SomeText,'$'
-
-
- SkipData:
-
- push ax dx ds cs
-
- pop ds
-
- mov dx,OFFSET cs:PrintMe
-
- mov ah,9
-
- int 21h
-
- pop ds dx ax
-
- endm
-
-
- endm
-
-
- The only problems with macros is that if you overuse them it leads
-
- to you program getting bigger and bigger and that you have problems
-
- with multiple definition of labels and variables. The correct way to
-
- solve this problem is to use the LOCAL directive for declaring names
-
- inside macros.
-
-
- Syntax:
-
- .LOCAL name
-
-
- Where name is the name of a local variable or label.
-
-
- Macros with parameters
-
- ---------------------------------------------------------------------
-
-
- Another useful property of macros is that they can have parameters.
-
- The number of parameters is only restricted by the length of the
-
- line.
-
-
- Syntax:
-
-
- Name_of_Macro macro par1,par2,par3
-
- ;
-
- ;commands go here
-
- ;
-
- endm
-
-
- This is an example that adds the first and second parameters and
-
- puts the result in the third:
-
-
- .AddMacro macro num1,num2,result
-
- ..push ax ;save ax from being destroyed
-
- ..mov ax,num1 ;put num1 into ax
-
- ..add ax,num2 ;add num2 to it
-
- ..mov result,ax ;move answer into result
-
- ..pop ax ;restore ax
-
- .endm
-
-
-
- FILES AND HOW TO USE THEM
-
- ---------------------------------------------------------------------
-
-
- Files can be opened, read and written to. DOS has some ways of doing
-
- this which save us the trouble of writing our own routines. Yes,
-
- more interrupts. Here is a list of helpful functions of interrupt
-
- 21h that deal with files.
-
-
- Note: Bits are numbered from right to left.
-
-
- Function 3Dh: open file
-
-
- Opens an existing file for reading, writing or appending on the
-
- specified drive and filename.
-
-
- INPUT:
-
- .AH = 3Dh
-
- .AL = bits 0-2 Access mode
-
- .. 000 = read only
-
- .. 001 = write only
-
- .. 010 = read/write
-
- . bits 4-6 Sharing mode (DOS 3+)
-
- .. 000 = compatibility mode
-
- .. 001 = deny all
-
- .. 010 = deny write
-
- .. 011 = deny read
-
- .. 100 = deny none
-
- .DS:DX = segment:offset of ASCIIZ pathname
-
-
- OUTPUT:
-
- .CF = 0 function is succesful
-
- .AX = handle
-
- .CF = 1 error has occured
-
- .AX = error code
-
- ..01h missing file sharing software
-
- ..02h file not found
-
- ..03h path not found or file does not exist
-
- ..04h no handle available
-
- ..05h access denied
-
- ..0Ch access mode not permitted
-
-
- What does ASCIIZ mean? An ASCIIZ string like a ASCII string with a
-
- zero on the end instead of a dollar sign.
-
-
- Important: Remember to save the file handle it is needed for later.
-
-
- How to save the file handle
-
-
- It is important to save the file handle because this is needed to do
-
- anything with the file. Well how is this done? There are two methods
-
- we could use: copy the file handle into another register and don't
-
- use that register or copy it to a variable in memory.
-
-
- The disadvantages with the first method is that you will have to
-
- remember not to use the register you saved it in and it wastes a
-
- register that can be used for something more useful. We are going to
-
- use the second. This is how it is done:
-
-
- .FileHandle DW 0 ;use this for saving the file handle
-
- ..
-
- ..
-
- ..
-
- .mov FileHandle,ax ;save the file handle
-
-
- Function 3Eh: close file
-
-
- Closes a file that has been opened.
-
-
- INPUT:
-
- .AX = 3Eh
-
- .BX = file handle
-
-
-
- OUTPUT:
-
- .CF = 0 function is successful
-
- .AX = destroyed
-
- .CF = 1 function not successful
-
- .AX = error code - 06h file not opened or unauthorised handle.
-
-
- Important: Don't call this function with a zero handle because that
-
- will close the standard input (the keyboard) and you won't be able
-
- to enter anything.
-
-
-
- Function 3Fh: read file/device
-
-
- Reads bytes from a file or device to a buffer.
-
-
- INPUT:
-
- .AH = 3Fh
-
- .BX = handle
-
- .CX = number of bytes to be read
-
- .DS:DX = segment:offset of a buffer
-
-
- OUTPUT:
-
- .CF = 0 function is successful
-
- .AX = number of bytes read
-
- .CF = 1 an error has occurred
-
- ..05h access denied
-
- ..06h illegal handle or file not opened
-
-
- If CF = 0 and AX = 0 then the file pointer was already at the end of
-
- the file and no more can be read. If CF = 0 and AX is smaller than
-
- CX then only part was read because the end of the file was reached
-
- or an error occurred.
-
-
- This function can also be used to get input from the keyboard. Use a
-
- handle of 0, and it stops reading after the first carriage return,
-
- or once a specified number of characters have been read. This is a
-
- good and easy method to use to only let the user enter a certain
-
- amount of characters.
-
-
- Listing 7: READFILE.ASM
-
-
- ;a program to demonstrate creating a file and then writing to
-
- ;it
-
-
- .model small
-
- .stack
-
- .code
-
-
- .mov ax,@data ;base address of data segment
-
- .mov ds,ax ;put this in ds
-
- .
-
- .mov dx,OFFSET FileName ;put address of filename in dx
-
- mov al,2 ;access mode - read and write
-
- .mov ah,3Dh ;function 3Dh -open a file
-
- .int 21h ;call DOS service
-
- mov Handle,ax ;save file handle for later
-
- .jc ErrorOpening ;jump if carry flag set - error!
-
- .
-
- .mov dx,offset Buffer ;address of buffer in dx
-
- .mov bx,Handle ;handle in bx
-
- .mov cx,100 ;amount of bytes to be read
-
- .mov ah,3Fh ;function 3Fh - read from file
-
- .int 21h ;call dos service
-
- jc ErrorReading ;jump if carry flag set - error!
-
-
- .mov bx,Handle ;put file handle in bx
-
- mov ah,3Eh ;function 3Eh - close a file
-
- int 21h ;call DOS service
-
- .
-
- mov cx,100 ;length of string
-
- mov si,OFFSET Buffer ;DS:SI - address of string
-
- .xor bh,bh ;video page - 0
-
- mov ah,0Eh ;function 0Eh - write character
-
-
- NextChar:
-
- .lodsb ;AL = next character in string
-
- int 10h ;call BIOS service
-
- .loop NextChar
-
-
- .mov ax,4C00h ;terminate program
-
- int 21h
-
-
- ErrorOpening:
-
- mov dx,offset OpenError ;display an error
-
- mov ah,09h ;using function 09h
-
- int 21h ;call DOS service
-
- mov ax,4C01h ;end program with an errorlevel =1
-
- int 21h
-
- ..
-
- ErrorReading:
-
- mov dx,offset ReadError ;display an error
-
- mov ah,09h ;using function 09h
-
- int 21h ;call DOS service
-
- ..
-
- mov ax,4C02h ;end program with an errorlevel =2
-
- int 21h
-
-
-
- .data
-
-
- Handle DW ? ;to store file handle
-
- FileName DB "C:\test.txt",0 ;file to be opened
-
-
- OpenError DB "An error has occured(opening)!$"
-
- ReadError DB "An error has occured(reading)!$"
-
-
- Buffer DB 100 dup (?) ;buffer to store data
-
-
- END
-
-
-
- Function 3Ch: Create file
-
-
- Creates a new empty file on a specified drive with a specified pathname.
-
-
- INPUT:
-
- .AH = 3Ch
-
- .CX = file attribute
-
- ..bit 0 = 1 read-only file
-
- ..bit 1 = 1 hidden file
-
- ..bit 2 = 1 system file
-
- ..bit 3 = 1 volume (ignored)
-
- ..bit 4 = 1 reserved (0) - directory
-
- ..bit 5 = 1 archive bit
-
- ..bits 6-15 reserved (0)
-
- DS:DX = segment:offset of ASCIIZ pathname
-
-
- OUTPUT:
-
- CF = 0 function is successful
-
- AX = handle
-
- CF = 1 an error has occurred
-
- ..03h path not found
-
- ..04h no available handle
-
- ..05h access denied
-
-
- Important: If a file of the same name exists then it will be lost.
-
- Make sure that there is no file of the same name. This can be done
-
- with the function below.
-
-
- Function 4Eh: find first matching file
-
-
- Searches for the first file that matches the filename given.
-
-
- INPUT:
-
- AH = 4Eh
-
- CX = file attribute mask (bits can be combined)
-
- ..bit 0 = 1 read only
-
- ..bit 1 = 1 hidden
-
- ..bit 2 = 1 system
-
- ..bit 3 = 1 volume label
-
- ..bit 4 = 1 directory
-
- ..bit 5 = 1 archive
-
- ..bit 6-15 reserved
-
- DS:DX = segment:offset of ASCIIZ pathname
-
-
- OUTPUT:
-
- CF = 0 function is successful
-
- [DTA] Disk Transfer Area = FindFirst data block
-
-
- The DTA block
-
-
- Offset Size in bytes Meaning
-
-
- 0 21 Reserved
-
- 21 1 File attributes
-
- 22 2 Time last modified
-
- 24 2 Date last modified
-
- 26 4 Size of file (in bytes)
-
- 30 13 File name (ASCIIZ)
-
-
- An example of checking if file exists:
-
-
- File DB "C:\file.txt",0 ;name of file that we want
-
-
- .mov dx,OFFSET File ;address of filename
-
- .mov cx,3Fh ;file mask 3Fh - any file
-
- .mov ah,4Eh ;function 4Eh - find first file
-
- .int 21h ;call DOS service
-
- .jc NoFile
-
- .
-
- .;print message saying file exists
-
- NoFile:
-
- .;continue with creating file
-
-
- This is an example of creating a file and then writing to it.
-
-
- Listing 8: CREATE.ASM
-
-
- ;This example program creates a file and then writes to it.
-
-
- .model small
-
- .stack
-
- .code
-
-
- mov ax,@data ;base address of data segment
-
- mov ds,ax ;put it in ds
-
-
- mov dx,offset StartMessage ;display the starting message
-
- mov ah,09h ;using function 09h
-
- int 21h ;call dos service
-
-
-
- mov dx,offset FileName ;put offset of filename in dx
-
- xor cx,cx ;clear cx - make ordinary file
-
- mov ah,3Ch ;function 3Ch - create a file
-
- int 21h ;call DOS service
-
- jc CreateError ;jump if there is an error
-
- .
-
- mov dx,offset FileName ;put offset of filename in dx
-
- mov al,2 ;access mode -read and write
-
- mov ah,3Dh ;function 3Dh - open the file
-
- int 21h ;call dos service
-
- jc OpenError ;jump if there is an error
-
- mov Handle,ax ;save value of handle
-
-
- mov dx,offset WriteMe ;address of information to write
-
- mov bx,Handle ;file handle for file
-
- mov cx,38 ;38 bytes to be written
-
- mov ah,40h ;function 40h - write to file
-
- int 21h ;call dos service
-
- jc WriteError ;jump if there is an error
-
- cmp ax,cx ;was all the data written?
-
- jne WriteError ;no it wasn't - error!
-
-
- mov bx,Handle ;put file handle in bx
-
- mov ah,3Eh ;function 3Eh - close a file
-
- int 21h ;call dos service
-
- .
-
- mov dx,offset EndMessage ;display the final message
-
- mov ah,09h ;using function 09h
-
- int 21h ;call dos service
-
-
-
- ReturnToDOS:
-
- mov ax,4C00h ;terminate program
-
- int 21h
-
-
- WriteError:
-
- mov dx,offset WriteMessage ;display an error message
-
- jmp EndError
-
-
- OpenError:
-
- mov dx,offset OpenMessage ;display an error message
-
- jmp EndError
-
-
- CreateError:
-
- mov dx,offset CreateMessage ;display an error message
-
-
- EndError:
-
- mov ah,09h ;using function 09h
-
- int 21h ;call dos service
-
- mov ax,4C01h ;terminate program
-
- int 21h
-
-
- .data
-
-
- CR equ 13
-
- LF equ 10
-
-
- StartMessage DB "This program creates a file called NEW.TXT" DB ,"on the C drive.$"
-
- EndMessage DB CR,LF,"File create OK, look at file to" DB ,"be sure.$"
-
-
- WriteMessage DB "An error has occurred (WRITING)$"
-
- OpenMessage DB "An error has occurred (OPENING)$"
-
- CreateMessage DB "An error has occurred (CREATING)$"
-
-
- WriteMe DB "HELLO, THIS IS A TEST, HAS IT WORKED?",0
-
-
- FileName DB "C:\new.txt",0 ;name of file to open
-
- Handle DW ? ;to store file handle
-
-
- END
-
-
- This is an example of how to delete a file after checking it exists:
-
-
- Listing 9: DELFILE.ASM
-
-
- ;a demonstration of how to delete a file. The file new.txt on
-
- ;c: is deleted (this file is created by create.exe). We also
-
- ;check if the file exits before trying to delete it
-
-
- .model small
-
- .stack
-
- .data
-
-
- CR equ 13
-
- LF equ 10
-
-
- File db "C:\new.txt",0
-
-
- Deleted db "Deleted file c:\new.txt$"
-
- NoFile db "c:\new.txt doesn't exits - exiting$"
-
- ErrDel db "Can't delete file - probably write protected$"
-
-
- .code
-
- .mov ax,@data ;set up ds as the segment for data
-
- .mov ds,ax ;use ax as we can't do it directly
-
-
- .mov dx,OFFSET File ;address of filename to look for
-
- mov cx,3Fh ;file mask 3Fh - any file
-
- .mov ah,4Eh ;function 4Eh - find first file
-
- .int 21h ;call dos service
-
- .jc FileDontExist
-
-
- mov dx,OFFSET File ;DS:DX points to file to be killed
-
- mov ah,41h ;function 41h - delete file
-
- int 21h ;call DOS service
-
- jc ErrorDeleting ;jump if there was an error
-
-
- .jmp EndOk
-
-
- EndOk:
-
- .mov dx,OFFSET Deleted ;display message
-
- jmp Endit
-
-
- ErrorDeleting:
-
- .mov dx,OFFSET ErrDel ;display message
-
- .jmp Endit
-
-
- FileDontExist:
-
- .mov dx,OFFSET NoFile ;display message
-
-
- EndIt:
-
- .mov ah,9
-
- .int 21h
-
- .
-
- .mov ax,4C00h ;terminate program and exit to DOS
-
- .int 21h ;call DOS service
-
-
- end
-
-
- USING THE FINDFIRST AND FINDNEXT FUNCTIONS
-
- ---------------------------------------------------------------------
-
-
- Listing 10: DIRC.ASM
-
-
- ;this program demonstrates how to look for files. It prints
-
- ;out the names of all the files in the c:\drive and names of
-
- ;the sub-directories
-
-
- .model small
-
- .stack
-
- .data
-
-
- FileName db "c:\*.*",0 ;file name
-
- DTA db 128 dup(?) ;buffer to store the DTA
-
- ErrorMsg db "An Error has occurred - exiting.$"
-
-
- .code
-
- mov ax,@data ;set up ds to be equal to the
-
- mov ds,a ;data segment
-
- mov es,ax ;also es
-
- ...
-
- mov dx,OFFSET DTA ;DS:DX points to DTA
-
- mov ah,1AH ;function 1Ah - set DTA
-
- int 21h ;call DOS service
-
-
- mov cx,3Fh ;attribute mask - all files
-
- mov dx,OFFSET FileName ;DS:DX points ASCIZ filename
-
- mov ah,4Eh ;function 4Eh - find first
-
- int 21h ;call DOS service
-
- jc error ;jump if carry flag is set
-
-
- LoopCycle:
-
- mov dx,OFFSET FileName ;DS:DX points to file name
-
- mov ah,4Fh ;function 4fh - find next
-
- int 21h ;call DOS service
-
- jc exit ;exit if carry flag is set
-
-
-
- mov cx,13 ;length of filename
-
- mov si,OFFSET DTA+30 ;DS:SI points to filename in DTA
-
- xor bh,bh ;video page - 0
-
- mov ah,0Eh ;function 0Eh - write character
-
-
- NextChar:
-
- lodsb ;AL = next character in string
-
- int 10h ;call BIOS service
-
- loop NextChar
-
-
- mov di,OFFSET DTA+30 ;ES:DI points to DTA
-
- mov cx,13 ;length of filename
-
- xor al,al ;fill with zeros
-
- rep stosb ;erase DTA
-
-
- jmp LoopCycle ;continue searching
-
-
- error:
-
- .mov dx,OFFSET ErrorMsg ;display error message
-
- .mov ah,9
-
- .int 21h
-
- exit:
-
- .mov ax,4C00h ;exit to DOS
-
- .int 21h
-
-
- end
-
-
- STRING INSTRUCTIONS
-
- ---------------------------------------------------------------------
-
-
- In assembly there are some very useful instructions for dealing with
-
- strings. Here is a list of the instructions and the syntax for using
-
- them:
-
-
- MOV* Move String: moves byte, word or double word at DS:SI
-
- to ES:DI
-
-
- Syntax:
-
-
- .movsb ;move byte
-
- .movsw ;move word
-
- .movsd ;move double word
-
-
- CMPS* Compare string: compares byte, word or double word at
-
- DS:SI to ES:DI
-
-
- Syntax:
-
-
- .cmpsb ;compare byte
-
- .cmpsw ;compare word
-
- .cmpsd ;compare double word
-
-
- Note: This instruction is normally used with the REP prefix.
-
-
- SCAS* Search string: search for AL, AX, or EAX in string at ES:DI
-
-
- Syntax:
-
- .
-
- .scasb ;search for AL
-
- .scasw ;search for AX
-
- .scasd ;search for EAX
-
-
- Note: This instruction is usually used with the REPZ or REPNZ prefix.
-
-
- REP Prefix for string instruction repeats instruction CX times
-
-
- Syntax:
-
-
- .rep StringInstruction
-
-
- STOS* Move byte, word or double word from AL, AX or EAX to ES:DI
-
-
- Syntax:
-
- .
-
- .stosb ;move AL into ES:DI
-
- .stosw ;move AX into ES:DI
-
- .stosd ;move EAX into ES:DI
-
-
-
- LODS* Move byte, word or double word from DS:SI to AL, AX or EAX
-
-
- Syntax:
-
-
- .lodsb ;move ES:DI into AL
-
- .lodsw ;move ES:DI into AX
-
- .lodsd ;move ES:DI into EAX
-
- .
-
- Listing 11: STRINGS.ASM
-
-
- ;This program demonstrates string examples
-
-
- .model small
-
- .stack
-
- .code
-
-
- mov ax,@data ;ax points to of data segment
-
- mov ds,ax ;put it into ds
-
- mov es,ax ;put it in es too
-
- .
-
- mov ah,9 ;function 9 - display string
-
- mov dx,OFFSET Message1 ;ds:dx points to message
-
- int 21h ;call dos function
-
-
- cld ;clear direction flag
-
-
- mov si,OFFSET String1 ;make ds:si point to String1
-
- mov di,OFFSET String2 ;make es:di point to String2
-
- mov cx,18 ;length of strings
-
- rep movsb ;copy string1 into string2
-
-
-
- mov ah,9 ;function 9 - display string
-
- mov dx,OFFSET Message2 ;ds:dx points to message
-
- int 21h ;call dos function
-
- .
-
- mov dx,OFFSET String1 ;display String1
-
- int 21h ;call DOS service
-
- .
-
- mov dx,OFFSET Message3 ;ds:dx points to message
-
- int 21h ;call dos function
-
- .
-
- mov dx,OFFSET String2 ;display String2
-
- int 21h ;call DOS service
-
-
- mov si,OFFSET Diff1 ;make ds:si point to Diff1
-
- mov di,OFFSET Diff2 ;make es:di point to Diff2
-
- mov cx,39 ;length of strings
-
- repz cmpsb ;compare strings
-
- jnz Not_Equal ;jump if they are not the same
-
- .
-
- mov ah,9 ;function 9 - display string
-
- mov dx,OFFSET Message4 ;ds:dx points to message
-
- int 21h ;call dos function
-
- .
-
- jmp Next_Operation
-
-
- Not_Equal:
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET Message5 ;ds:dx points to message
-
- .int 21h ;call dos function
-
- .
-
- Next_Operation:
-
- .mov di,OFFSET SearchString ;make es:di point to string
-
- .mov cx,36 ;length of string
-
- .mov al,'H' ;character to search for
-
- .repne scasb ;find first match
-
- .jnz Not_Found
-
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET Message6 ;ds:dx points to message
-
- .int 21h ;call dos function
-
-
- .jmp Lodsb_Example
-
-
- Not_Found:
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET Message7 ;ds:dx points to message
-
- .int 21h ;call dos function
-
-
- Lodsb_Example:
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET NewLine ;ds:dx points to message
-
- .int 21h ;call dos function
-
-
- .mov cx,17 ;length of string
-
- mov si,OFFSET Message ;DS:SI - address of string
-
- xor bh,bh ;video page - 0
-
- .mov ah,0Eh ;function 0Eh - write character
-
- NextChar:
-
- lodsb ;AL = next character in string
-
- int 10h ;call BIOS service
-
- loop NextChar
-
-
- mov ax,4C00h ;return to DOS
-
- int 21h
-
-
- .data
-
-
- CR equ 13
-
- LF equ 10
-
-
- String1 db "This is a string!$"
-
- String2 db 18 dup(0)
-
-
- Diff1 db "This string is nearly the same as Diff2$"
-
- Diff2 db "This string is nearly the same as Diff1$"
-
-
- Equal1 db "The strings are equal$"
-
- Equal2 db "The strings are not equal$"
-
-
- SearchString db "1293ijdkfjiu938uHello983fjkfjsi98934$"
-
-
-
- Message db "This is a message"
-
-
- Message1 db "Using String instructions example program.$"
-
- Message2 db CR,LF,"String1 is now: $"
-
- Message3 db CR,LF,"String2 is now: $"
-
- Message4 db CR,LF,"Strings are equal!$"
-
- Message5 db CR,LF,"Strings are not equal!$"
-
- Message6 db CR,LF,"Character was found.$"
-
- Message7 db CR,LF,"Character was not found.$"
-
-
- NewLine db CR,LF,"$"
-
-
- end
-
-
- HOW TO FIND OUT THE DOS VERSION
-
- ---------------------------------------------------------------------
-
-
- In many programs it is necessary to find out what the DOS version
-
- is. This could be because you are using a DOS function that needs
-
- the revision to be over a certain level.
-
-
- Firstly this method simply finds out what the version is.
-
-
- .mov ah,30h ;function 30h - get MS-DOS version
-
- .int 21h ;call DOS function
-
-
- This function returns the major version number in AL and the minor
-
- version number in AH. For example if it was version 4.01, AL would
-
- be 4 and AH would be 01. The problem is that if on DOS 5 and higher
-
- SETVER can change the version that is returned. The way to get round
-
- this is to use this method.
-
-
- .mov ah,33h ;function 33h - actual DOS version
-
- .mov al,06h ;subfunction 06h
-
- .int 21h ;call interrupt 21h
-
-
- This will only work on DOS version 5 and above so you need to check
-
- using the former method. This will return the actual version of DOS
-
- even if SETVER has changed the version. This returns the major
-
- version in BL and the minor version in BH.
-
-
- MULTIPLE PUSHES AND POPS
-
- ---------------------------------------------------------------------
-
-
- You can push and pop more than one register on a line in TASM and
-
- A86. This makes your code easier to understand.
-
-
- .push ax bx cx dx ;save registers
-
- .pop dx cx bx ax ;restore registers
-
-
- When TASM (or A86) compiles these lines it translates it into
-
- separate pushes an pops. This way just saves you time typing and
-
- makes it easier to understand.
-
-
- Note: To make these lines compile in A86 you need to put commas (,)
-
- in between the registers.
-
-
- THE PUSHA/PUSHAD AND POPA/POPAD INSTRUCTIONS
-
- ---------------------------------------------------------------------
-
-
- PUSHA is a useful instruction that pushes all general purpose
-
- registers onto the stack. It accomplishes the same as the following:
-
-
- .temp = SP
-
- .push ax
-
- .push cx
-
- .push dx
-
- .push bx
-
- .push temp
-
- .push bp
-
- .push si
-
- .push di
-
-
- The main advantage is that it is less typing, a smaller instruction
-
- and it is a lot faster. POPA does the reverse and pops these
-
- registers off the stack. PUSHAD and POPAD do the same but with the
-
- 32-bit registers ESP, EAX, ECX, EDX, EBX, EBP, ESI and EDI.
-
-
- USING SHIFTS FOR FASTER MULTIPLICATION AND DIVISION
-
- ---------------------------------------------------------------------
-
-
- Using MUL's and DIV's is very slow and should be only used when
-
- speed is not needed. For faster multiplication and division you can
-
- shift numbers left or right one or more binary positions. Each shift
-
- is to a power of 2. This is the same as the << and >> operators in
-
- C. There are four different ways of shifting numbers either left or
-
- right one binary position.
-
-
- SHL Unsigned multiple by two
-
- SHR Unsigned divide by two
-
- SAR Signed divide by two
-
- SAL same as SHL
-
-
- The syntax for all four is the same.
-
-
- Syntax:
-
- SHL operand1,operand2
-
-
- Note: The 8086 cannot have the value of opperand2 other than 1.
-
- 286/386 cannot have operand2 higher than 31.
-
-
- LOOPS
-
- ---------------------------------------------------------------------
-
-
- Using Loop is a better way of making a loop then using JMP's. You
-
- place the amount of times you want it to loop in the CX register and
-
- every time it reaches the loop statement it decrements CX (CX-1) and
-
- then does a short jump to the label indicated. A short jump means
-
- that it can only 128 bytes before or 127 bytes after the LOOP
-
- instruction.
-
-
- Syntax:
-
- .mov cx,100 ;100 times to loop
-
- Label:
-
- ..
-
- ..
-
- ..
-
- .Loop Label: ;decrement CX and loop to Label
-
-
- This is exactly the same as the following piece of code without
-
- using loop:
-
-
- .mov cx,100 ;100 times to loop
-
- Label:
-
- .dec cx ;CX = CX-1
-
- .jnz Label ;continue until done
-
-
- Which do you think is easier to understand? Using DEC/JNZ is faster
-
- on 486's and above and it is useful as you don't have to use CX.
-
-
- This works because JNZ will jump if the zero flag has not been set.
-
- Setting CX to 0 will set this flag.
-
-
- HOW TO USE A DEBUGGER
-
- ---------------------------------------------------------------------
-
-
- This is a good time to use a debugger to find out what your program
-
- is actually doing. I am going to demonstrate how to use Turbo
-
- Debugger to check what the program is actually doing. First we need
-
- a program which we can look at.
-
-
- Listing 12: DEBUG.ASM
-
-
- ;example program to demonstrate how to use a debugger
-
-
- .model tiny
-
- .code
-
- org 100h
-
- start:
-
-
- .push ax ;save value of ax
-
- .push bx ;save value of bx
-
- .push cx ;save value of cx
-
- .
-
- .mov ax,10 ;first parameter is 10
-
- .mov bx,20 ;second parameter is 20
-
- .mov cx,3 ;third parameter is 3
-
- .
-
- .Call ChangeNumbers ;call procedure
-
- .
-
- .pop cx ;restore cx
-
- .pop bx ;restore bx
-
- .pop ax ;restore dx
-
-
- .mov ax,4C00h ;exit to dos
-
- .int 21h
-
-
- ChangeNumbers PROC
-
- .add ax,bx ;adds number in bx to ax
-
- .mul cx ;multiply ax by cx
-
- .mov dx,ax ;return answer in dx
-
- .ret
-
- ChangeNumbers ENDP
-
-
- end start
-
-
- Now compile it to a .COM file and then type:
-
-
- .td name of file
-
-
- Turbo Debugger then loads. You can see the instructions that make up
-
- your programs, for example the first few lines of this program is
-
- shown as:
-
- .
-
- .cs:0000 50 push ax
-
- .cs:0001 53 push bx
-
- .cs:0002 51 push cx
-
-
- Some useful keys for Turbo Debugger:
-
-
- F5 Size Window
-
- F7 Next Instruction
-
- F9 Run
-
- ALT F4 Step Backwards
-
-
- .
-
- The numbers that are moved into the registers are different that the
-
- ones that in the source code because they are represented in their
-
- hex form (base 16) as this is the easiest base to convert to and
-
- from binary and that it is easier to understand than binary also.
-
-
- At the left of this display there is a box showing the contents of
-
- the registers. At this time all the main registers are empty. Now
-
- press F7 this means that the first line of the program is run. As
-
- the first line pushed the AX register into the stack, you can see
-
- that the stack pointer (SP) has changed. Press F7 until the line
-
- which contains mov ax,000A is highlighted. Now press it again. Now
-
- if you look at the box which contains the contents of the registers
-
- you can see that AX contains A. Press it again and BX now contains
-
- 14, press it again and CX contains 3. Now if you press F7 again you
-
- can see that AX now contains 1E which is A+14. Press it again and
-
- now AX contains 5A 1E multiplied by 3. Press F7 again and you will
-
- see that DX now also contains 5A. Press it three more times and you
-
- can see that CX, BX and AX are all set back to their original values
-
- of zero.
-
-
- MORE OUTPUT IN TEXT MODES
-
- ---------------------------------------------------------------------
-
-
- I am going to cover some more ways of outputting text in text modes.
-
- This first program is an example of how to move the cursor to
-
- display a string of text where you want it to go.
-
-
- Listing 12: TEXT1.ASM
-
-
- .model tiny
-
- .code
-
- org 100h
-
- start:
-
- .mov dh,12 ;cursor col
-
- .mov dl,32 ;cursor row
-
- .mov ah,02h ;move cursor to the right place
-
- .xor bh,bh ;video page 0
-
- .int 10h ;call bios service
-
-
- .mov dx,OFFSET Text ;DS:DX points to message
-
- .mov ah,9 ;function 9 - display string
-
- .int 21h ;call dos service
-
-
- .mov ax,4C00h ;exit to dos
-
- .int 21h
-
-
- Text DB "This is some text$"
-
-
- This next example demonstrates how to write to the screen using the
-
- file function 40h of interrupt 21h.
-
-
- Listing 13: TEXT2.ASM
-
-
- end start
-
- .model small
-
- .stack
-
- .code
-
- .mov ax,@data ;set up ds as the segment for data
-
- .mov ds,ax ;put this in ds
-
- .
-
- .mov ah,40h ;function 40h - write file
-
- .mov bx,1 ;handle = 1 (screen)
-
- .mov cx,17 ;length of string
-
- .mov dx,OFFSET Text ;DS:DX points to string
-
- .int 21h ;call DOS service
-
- .
-
- .mov ax,4C00h ;terminate program
-
- .int 21h
-
-
- .data
-
-
- Text DB "This is some text"
-
-
- end
-
-
- The next program shows how to set up and call function 13h of
-
- interrupt 10h - write string. This has the advantages of being able
-
- to write a string anywhere on the screen in a specified colour but
-
- it is hard to set up.
-
-
- Listing 14: TEXT3.ASM
-
-
- .model small
-
- .stack
-
- .code
-
- .mov ax,@data ;set up ds as the segment for data
-
- .mov es,ax ;put this in es
-
- .mov bp,OFFSET Text ;ES:BP points to message
-
-
- .mov ah,13h ;function 13 - write string
-
- .mov al,01h ;attrib in bl,move cursor
-
- .xor bh,bh ;video page 0
-
- .mov bl,5 ;attribute - magenta
-
- .mov cx,17 ;length of string
-
- .mov dh,5 ;row to put string
-
- .mov dl,5 ;column to put string
-
- .int 10h ;call BIOS service
-
- .
-
- .mov ax,4C00h ;return to DOS
-
- .int 21h
-
-
- .data
-
-
- Text DB "This is some text"
-
- end
-
-
- The next program demonstrates how to write to the screen using rep
-
- stosw to put the writing in video memory.
-
-
- Listing 15: TEXT4.ASM
-
-
- .model small
-
- .stack
-
- .code
-
- .mov ax,0B800h ;segment of video buffer
-
- .mov es,ax ;put this into es
-
- .xor di,di ;clear di, ES:DI points to video memory
-
- .mov ah,4 ;attribute - red
-
- .mov al,"G" ;character to put there
-
- .mov cx,4000 ;amount of times to put it there
-
- .cld ;direction - forwards
-
- .rep stosw ;output character at ES:[DI]
-
- .
-
- .mov ax,4C00h ;return to DOS
-
- .int 21h
-
-
- end
-
-
-
- The next program demonstrates how to write a string to video memory.
-
-
- Listing 15: DIRECTWR.ASM
-
-
- ;write a string direct to video memory
-
-
- .model small
-
- .stack
-
- .code
-
- .mov ax,@data
-
- .mov ds,ax
-
- .
-
- .mov ax,0B800h ;segment of video buffer
-
- .mov es,ax ;put this into es
-
- .
-
- .mov ah,3 ;attribute - cyan
-
- .mov cx,17 ;length of string to print
-
- .mov si,OFFSET Text ;DX:SI points to string
-
- .xor di,di
-
-
- Wr_Char:
-
- .lodsb ;put next character into al
-
- .mov es:[di],al ;output character to video memory
-
- .inc di ;move along to next column
-
- .mov es:[di],ah ;output attribute to video memory
-
- .inc di
-
- .loop Wr_Char ;loop until done
-
- .
-
- .mov ax,4C00h ;return to DOS
-
- .int 21h
-
- .
-
- .data
-
-
- Text DB "This is some text"
-
-
- end
-
-
- It is left as an exercise to the reader to modify it so that only
-
- one write is made to video memory.
-
-
- MODE 13h
-
- ---------------------------------------------------------------------
-
-
- Mode 13h is only available on VGA, MCGA cards and above. The reason
-
- that I am talking about this card is that it is very easy to use for
-
- graphics because of how the memory is arranged.
-
-
- FIRST CHECK THAT MODE 13h IS POSSIBLE
-
- ---------------------------------------------------------------------
-
-
- It would be polite to tell the user if his/her computer cannot
-
- support mode 13h instead of just crashing his computer without
-
- warning. This is how it is done.
-
-
- Listing 16: CHECK13.ASM
-
-
- .model small
-
- .stack
-
- .data
-
-
- NoSupport db "Mode 13h is not supported on this computer."
-
- ..db ,"You need either a MCGA or VGA video" db ,"card/monitor.$"
-
- Supported db "Mode 13h is supported on this computer.$"
-
-
- .code
-
-
- .mov ax,@data ;set up DS to point to data segment
-
- .mov ds,ax ;use ax
-
-
- .call Check_Mode_13h ;check if mode 13h is possible
-
- .jc Error ;if cf=1 there is an error
-
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET Supported ;DS:DX points to message
-
- .int 21h ;call DOS service
-
-
- .jmp To_DOS ;exit to DOS
-
-
- Error:
-
- .mov ah,9 ;function 9 - display string
-
- .mov dx,OFFSET NoSupport ;DS:DX points to message
-
- .int 21h ;call DOS service
-
-
- To_DOS:
-
- .mov ax,4C00h ;exit to DOS
-
- .int 21h
-
-
- Check_Mode_13h PROC ;Returns: CF = 1 Mode 13h not possible
-
- .
-
- .mov ax,1A00h ;Request video info for VGA
-
- .int 10h ;Get Display Combination Code
-
- .cmp al,1Ah ;Is VGA or MCGA present?
-
- .je Mode_13h_OK ;mode 13h is supported
-
- .stc ;mode 13h isn't supported CF=1
-
-
- Mode_13h_OK:
-
- .ret
-
-
- Check_Mode_13h ENDP
-
-
- end
-
-
- Just use this to check if mode 13h is supported at the beginning of
-
- your program to make sure that you can go into that mode.
-
-
- SETTING THE VIDEO MODE
-
- ---------------------------------------------------------------------
-
-
- It is very simple to set the mode. This is how it is done.
-
-
- .mov ax,13h ;set mode 13h
-
- .int 10h ;call BIOS service
-
-
- Once we are in mode 13h and have finished what we are doing we need
-
- to we need to set it to the video mode that it was in previously.
-
- This is done in two stages. Firstly we need to save the video mode
-
- and then reset it to that mode.
-
-
- VideoMode db ?
-
- ....
-
- .mov ah,0Fh ;function 0Fh - get current mode
-
- .int 10h ;Bios video service call
-
- .mov VideoMode,al ;save current mode
-
-
- .;program code here
-
-
- .mov al,VideoMode ;set previous video mode
-
- .xor ah,ah ;clear ah - set mode
-
- .int 10h ;call bios service
-
- .mov ax,4C00h ;exit to dos
-
- .int 21h ;call dos function
-
-
- Now that we can get into mode 13h lets do something. Firstly lets
-
- put some pixels on the screen.
-
-
- Function 0Ch: Write Graphics Pixel
-
-
- This makes a colour dot on the screen at the specified graphics
-
- coordinates.
-
-
- INPUT:
-
- .AH = 0Ch
-
- .AL = Color of the dot
-
- .CX = Screen column (x coordinate)
-
- .DX = Screen row (y coordinate)
-
-
- OUTPUT:
-
- .Nothing except pixel on screen.
-
-
- Note: This function performs exclusive OR (XOR) with the new colour
-
- value and the current context of the pixel of bit 7 of AL is set.
-
-
- This program demonstrates how to plot pixels. It should plot four
-
- red pixels into the middle of the screen.
-
-
- Listing 17: PIXINT.ASM
-
-
- ;example of plotting pixels in mode 13 using bios services -
-
- ;INT 10h
-
-
- .model tiny
-
- .code
-
- org 100h
-
-
- start:
-
- .mov ax,13 ;mode = 13h
-
- .int 10h ;call bios service
-
-
- .mov ah,0Ch ;function 0Ch
-
- .mov al,4 ;color 4 - red
-
- .mov cx,160 ;x position = 160
-
- .mov dx,100 ;y position = 100
-
- .int 10h ;call BIOS service
-
- .
-
- .inc dx ;plot pixel downwards
-
- .int 10h ;call BIOS service
-
- .inc cx ;plot pixel to right
-
- .int 10h ;call BIOS service
-
- .dec dx ;plot pixel up
-
- .int 10h ;call BIOS service
-
-
- .xor ax,ax ;function 00h - get a key
-
- .int 16h ;call BIOS service
-
- .mov ax,3 ;mode = 3
-
- .int 10h ;call BIOS service
-
-
- .mov ax,4C00h ;exit to DOS
-
- .int 21h
-
-
- end start
-
-
- SOME OPTIMIZATIONS
-
- ---------------------------------------------------------------------
-
-
- This method isn't too fast and we could make it a lot faster. How?
-
- By writing direct to video memory. This is done quite easily.
-
-
- The VGA segment is 0A000h. To work out where each pixel goes you use
-
- this simple formula to get the offset.
-
-
- .Offset = X + ( Y x 320 )
-
-
- All we do is to put a number at this location and there is now a
-
- pixel on the screen. The number is what colour it is.
-
-
- There are two instructions that we can use to put a pixel on the
-
- screen, firstly we could use stosb to put the value in AL to ES:DI
-
- or we can use a new form of the MOV instruction like this:
-
-
- .mov es:[di], color
-
-
- Which should we use? When we are going to write pixels to the screen
-
- we need to do so as fast as it is possible.
-
-
- Instruction Pentium 486 386 286 86
-
-
- STOSB 3 5 4 3 11
-
- MOV AL to SEG:OFF 1 1 4 3 10
-
-
- If you use the MOV method you may need to increment DI (which STOSB
-
- does).
-
-
- [ put pixel instruction]
-
-
- If we had a program which used sprites which need to be continuously
-
- draw, erased and then redraw you will have problems with flicker. To
-
- avoid this you can use a 'double buffer'. This is another part of
-
- memory which you write to and then copy all the information onto the
-
- screen.
-
-